import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

class HighlightInfo {
  HighlightInfo({required this.highlight, required this.text});

  final bool highlight;
  final String text;

  static List<HighlightInfo> parseHighlightText(
      String text, String highlightText,
      {int startIndex = 0, bool matchAllHighlightText = true}) {
    List<HighlightInfo> infoList = [];

    {
      int length = text.length;
      if (!matchAllHighlightText) {
        bool highlight = false;
        String? currentText;
        for (int i = 0; i < length; ++i) {
          String s = text[i];
          if (i >= startIndex && highlightText.contains(s)) {
            if (highlight == false && currentText != null) {
              infoList
                  .add(HighlightInfo(highlight: highlight, text: currentText));
              currentText = null;
            }

            highlight = true;
            currentText = (currentText ?? '') + s;
          } else {
            if (highlight == true && currentText != null) {
              infoList
                  .add(HighlightInfo(highlight: highlight, text: currentText));
              currentText = null;
            }

            highlight = false;
            currentText = (currentText ?? '') + s;
          }
        }

        if (currentText != null) {
          infoList.add(HighlightInfo(highlight: highlight, text: currentText));
        }
      } else {
        int start = startIndex;
        do {
          int index = text.indexOf(highlightText, start);
          if (index == -1) {
            infoList.add(
                HighlightInfo(highlight: false, text: text.substring(start)));
            break;
          } else {
            if (index - start > 0) {
              infoList.add(HighlightInfo(
                  highlight: false,
                  text: text.substring(start, index - start)));
            }
            infoList.add(HighlightInfo(
                highlight: true,
                text: text.substring(index, index + highlightText.length)));
            start = index + highlightText.length;
            if (start >= length) {
              break;
            }
          }
        } while (true);
      }
    }

    return infoList;
  }
}

typedef AppendTextSpanCallback = void Function(TextSpanBuilder textSpanBuilder);

class TextSpanBuilder {
  TextSpanBuilder({required this.style, required this.highlightTextStyle});

  final TextStyle style;
  final TextStyle highlightTextStyle;

  List<InlineSpan> _textSpanList = [];

  void appendText(String text, {VoidCallback? tapCallback}) {
    _textSpanList.add(
      TextSpan(
        text: text,
        style: style,
        recognizer: _setupTapGestureRecognizer(tapCallback),
      ),
    );
  }

  void appendHighlightText(String text,
      {TextStyle? highlightTextStyle,
      VoidCallback? tapCallback,
      bool useButton = false}) {
    if (highlightTextStyle == null) {
      highlightTextStyle = this.highlightTextStyle;
    }

    late InlineSpan span;
    if (useButton) {
      span = WidgetSpan(
        child: CupertinoButton(
          padding: EdgeInsets.zero,
          color: Colors.transparent,
          disabledColor: Colors.transparent,
          borderRadius: null,
          minSize: null,
          child: Text(
            text,
            style: highlightTextStyle,
          ),
          onPressed: tapCallback,
        ),
      );
    } else {
      span = TextSpan(
        text: text,
        style: highlightTextStyle,
        recognizer: _setupTapGestureRecognizer(tapCallback),
      );
    }

    _textSpanList.add(span);
  }

  void appendWidget(Widget child) {
    _textSpanList.add(WidgetSpan(child: child));
  }

  TapGestureRecognizer? _setupTapGestureRecognizer(VoidCallback? callback) {
    if (callback == null) {
      return null;
    }
    return TapGestureRecognizer()..onTap = callback;
  }

  void reset() {
    _textSpanList.clear();
  }

  TextSpan? assembleTextSpan({VoidCallback? tapCallback}) {
    if (_textSpanList.length == 0) {
      return null;
    }
    return TextSpan(
      children: _textSpanList.toList(growable: false),
      recognizer: _setupTapGestureRecognizer(tapCallback),
    );
  }
}
